﻿namespace JoinBox.Forms;

using JoinBox.Basal;
using System;

/// <summary>
/// 线程上下文/子类化拦截消息
/// </summary>
public class SyncEx : SyncContext, IDisposable
{
    /// <summary>
    /// 句柄
    /// </summary>
    public IntPtr Handle => _nativeCallProc.Handle;

    /// <summary>
    /// 子类化窗体对象
    /// </summary>
    readonly NativeCallProc _nativeCallProc;

    /// <summary>
    /// 子类化窗体上下文
    /// </summary>
    /// <param name="windowHandle">嵌入到此句柄的窗体</param>
    /// <exception cref="ArgumentException"></exception>
    public SyncEx(IntPtr windowHandle)
    {
        if (windowHandle == IntPtr.Zero)
            throw new ArgumentException("子类化失败,句柄为空");

        _nativeCallProc = new(windowHandle);

        /// 如果从来不实现,
        /// 会导致 <see cref="SyncContext.ExistContextCache"/> 永远不存在
        /// 因此在此处进行必然的一次实现
        WndProc(msg => {
            return true;
        });
    }

    /// <summary>
    /// 消息循环
    /// </summary>
    /// <param name="WndProc">消息,true不拦截回调</param>
    public void WndProc(Func<System.Windows.Forms.Message, bool> wndProc)
    {
        // 把上下文获取加入委托内
        // 这是错误的做法
        //WndProc += msg => {
        //    WaitOne();
        //    return true;
        //};

        // 这才是对的做法
        _nativeCallProc.WndProc(msg => {
            WaitOne();
            return wndProc.Invoke(msg);
        });
    }

    #region IDisposable接口相关函数
    public bool IsDisposed { get; private set; } = false;

    /// <summary>
    /// 手动调用释放
    /// </summary>
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    /// <summary>
    /// 析构函数调用释放
    /// </summary>
    ~SyncEx()
    {
        Dispose(false);
    }

    protected virtual void Dispose(bool disposing)
    {
        // 不重复释放
        if (IsDisposed) return;
        IsDisposed = true;

        _nativeCallProc.Dispose();
    }
    #endregion
}

public class SyncEx2Form : Basal.SyncContext
{
    public System.Windows.Forms.Form? Window;

    /// <summary>
    /// 处理Form上下文
    /// </summary>
    /// <param name="window"></param>
    public SyncEx2Form(System.Windows.Forms.Form window)
    {
        Window = window ?? throw new ArgumentNullException(nameof(window));
    }

    /// <summary>
    /// 加载事件,因为显示之后才确定分配了线程
    /// </summary>
    public void Loaded()// object? sender = null/*, RoutedEventArgs? e = null*/
    {
        // 空闲时候执行的事件-cad08直接非Debug用不了
        System.Windows.Forms.Application.Idle += (sender, e) => {
            WaitOne();
        };
    }
}